昨天介紹的 Azure App Service (Linux) 雲端PaaS服務,除了可以使用傳統的程式碼使用 Visual Studio/ Azure Cli指令打包zip方式部署之外,由於底層是使用 Docker Container 作為基礎架構,因此也可以使用自製 Docker Container Image 的方式來部署應用程式,利用Azure App Service提供 "持續部署(Continuous Deployment)" 功能,配合 Azure Container Registry 這個提供建置/管理容器影像的雲端服務,實現極簡版的 CI/CD 流程。
以下是在不用正式的CI/CD服務如Azure DevOps, GitHub Action情況下,包含持續部署流程的Azure服務組成範例架構:
這個和之前的架構上差異:不使用Deployment Slot了,並且新增一個 Azure Container Registry (以下簡稱 ACR )服務,用來建置/管理/儲存容器影像(Container Image)。
沒有使用 Deployment Slot 的原因是:由於 App Service 在使用自訂容器影像檔(Custom Container Image)部署方式的持續部署(Continuous Deployment)功能時,會讓 App Service Deployment Slot 在 "Slot swap" 後交換下來的應用服務實體,自動部署其持續部署功能頁所設定使用之容器影像檔名稱(含影像標籤);導致換下來的舊版本應用服務實體在Slow swap交換成功後,就又自動被持續部署功能把舊版本應用服務實體替換成使用當前版的容器影像檔部署再重新啟動起來了:
這樣就失去原本採用 Deployment Slot 用來暫時保留舊版應用的運營面目的,為了要補足這方面的缺點,就得採用ACR(Azure Container Registry)服務來管理&儲存部署過的容器影像版本。
微軟ACR服務可以在開發端使用 azure cli 指令列工具,進行容器影像的上傳,或是更簡便一點,直接將ACR當作可遠端操控的雲端 container image build server,將本機端的工作目錄內的檔案內容上傳到ACR並自動建立容器影像檔;ACR還能設定在容器影像檔建立完成或上傳完畢後,觸發ACR的 "Webhook" 功能,以便通知 Azure App Service 服務現在有新版本可部署到服務機了。
Azure App Service 的持續部署功能設定之後,會提供一個可供其他整合服務使用的Webhook呼叫點,以通知App Service本身進行所設定的持續部署行為:將容器影像部署到 Azure App Service 服務上。此呼叫點的網址就是上一段所介紹的,ACR的Webhook功能所呼叫網址,這樣就可以實現從開發者端電腦上傳專案程式碼內容到ACR成為容器影像檔,再自動部署到 Azure App Service 服務的整個流程。
當然實務上建議,從開發者電腦到ACR的這段流程,還是要串接正式的原始碼版本管理服務以及CI/CD服務如Azure DevOps, GitHub Action來協助從開發到運營的完整工作流程,這樣可以有程式碼檔案版本管理功能以及保存原始碼,並且可以進行自動測試,以確保程式碼的品質。
短網址服務範例專案(原始碼:https://github.com/windperson/OrleansUrlShortener/tree/AzureWebApp-CustomContainer ),建置前一節介紹Azure服務架構的Bicep程式碼位於 infra/Azure/AppService_CustomContainer 目錄下,包含了六個 *.bicep檔案以及一個 parameters.json ,這是用來提供執行Azure Cli部署指令時大部分參數預設值的設定檔案。
要建立短網址服務的Azure資源,安裝 Azure CLI並登入後,在 infra/Azure/AppService_CustomContainer 目錄執行以下指令:
az deployment sub create --name orleans_net6webapp_linux_demo02 --location [azure_datacenter_region] --template-file ./main.bicep --parameters deploy_region=[azure_datacenter_region] ./parameters.json
其中 --name
參數是此部署的名稱,可自訂,在此範例使用 orleans_net6webapp_linux_demo02,而 [azure_datacenter_region]
要替換成你想要部署的Azure資料中心區域的縮寫名稱,例如 eastus
、westus
、southeastasia
等等;可使用Azure CLI的 az account list-locations -o table
指令來取得可部署的區域名稱。
部署指令下達之後,稍等一段執行時間後,假如回傳的Json字串有 "provisoningState": ""Succeeded"
,則表示Azure資源的建置部署指令成功,可進行後續的程式上版動作:
此時在Azure Portal管理網頁的資源群組(resource group)列表內可以看到名稱為 orleans_net6container_demo 的新建資源群組(此名稱為寫在該目錄下 parameters.json 檔的 resource_group
參數),以及包含的App Service Plan, App Service (Linux), Deployment slot, Storage Account, Managed Identity, Container Registry, Container Registry webhook 等等總共9個Azure服務資源:
當不需要此短網址服務的Azure資源,需要移除掉時:
az deployment sub delete --name orleans_net6webapp_linux_demo02
az group delete --name orleans_net6container_demo
此版本的Bicep程式碼和昨天的 App Service (Linux) 不同的是:
kind
屬性值(第31行)要寫成 app,linux,container (要注意逗號間不可有空白)之外,還需要第44行 linuxFxVersion
屬性設定為:
DOCKER|<ACR_Registry_Name>.azurecr.io/<Container_Image_Name>:<Tag>
的格式,此格式為 Azure App Service 持續部署功能指定容器影像倉庫(container registry)、影像檔名稱與影像檔標籤的方法。DOCKER_REGISTRY_SERVER_USERNAME
和 DOCKER_REGISTRY_SERVER_PASSWORD
這兩個設定值,假如是其他例如 Docker Hub、GitHub Container Registry 等等的容器影像倉庫,則需要在Bicep配置 appSettings 的程式碼中明確增加這兩個設定,以便提供持續部署的系統服務存取容器影像倉庫的帳號密碼資訊,讓App Service有辦法成功存取到容器影像倉庫的影像檔案,而且還要在 appSettings 多新增一個 DOCKER_ENABLE_CI
的設定,其值為 true
,這樣才能啟動用容器影像持續部署的功能。acrUseManagedIdentityCreds
設定,設為 true
,就是指定App Service使用 Azure Managed Identity 的授權方式對ACR操作,第50行則是指定對ACR有操作權限的 User Defined Managed Identity 資源。WEBSITES_ENABLE_APP_SERVICE_STORAGE
的值為 false
,此設定值如果沒明確設定的話,預設值是true,這個設定是App Service原本使用程式碼部署的方式時,App Service會在執行實體的檔案系統中留一個掛載的網路檔案目錄,用來存放應用程式執行的二進位檔或script程式碼之用,以便讓執行實體之間可以共用此種儲存空間,當需要水平擴充(scale-out)時減少需要重複拷貝的檔案,在使用容器影像部署的方式時,就不需要這個功能了,因此藉由將此功能停用,以減少App Service的應用服務執行實體空間使用量。princiaplId
回傳給呼叫端之外,在第124~125行使用了呼叫Bicep的 resourceId()
這個可以取得Azure雲端資源唯一識別ID的內建函式,來取得沒有開放出Bicep屬性定義的持續部署webhook網址,做為給呼叫端的回傳參數 DeployWebhookUrl
:principalId
作為參數傳入 acr.bicep
模組,以便在之後設定存取ACR權限時使用。webapp.bicep
模組建立App Service時回傳的 "DeployWebhookUrl" 網址參數,在第65行用來組合成Bicep陣列物件,以便讓 webhookUrls
這個Bicep模組的輸入參數在實際建立ACR時使用。action
則是定義當container image被上傳(push)時,此webhook才會被觸發。webhookUrls
在第40、41、43行設定對應的webhook呼叫功能:其他一些定義實際參數值的寫法是為了要符合Azure雲端服務的各種資源命名規則所對應的寫法,例如 main.bicep 檔案在第20行定義要用來指定為ACR服務名稱的變數取值方式就類似於App Service的取名機制,以達到全Azure雲端唯一識別的名稱,畢竟ACR的服務名稱會結合Azure給予的預設網域名稱結尾字串成為 <ACR服務名稱>.azurecr.io
的存取網址,而此網址不能和Azure上既有的ACR服務重複。
要讓ACR建立短網址服務的容器影像檔並讓整個持續部署的流程自動動起來的最簡單方法,就是在短網址範例專案 git clone 下來後的根目錄,使用如下的Azure CLI指令,將專案內容上傳給ACR執行容器影像建置:
az acr build --no-logs -t urlshortener/frontend:latest <ACR_service_name> -f src/UrlShortener.Frontend/Dockerfile .
記得要將 <ACR_service_name>
替換成前面使用Bicep建立的ACR服務名稱,-t
參數表示我們要將此欲打包的容器影像檔名稱為 urlshortener/frontend,並且設定容器影像檔標籤為 latest;而 src/UrlShortener.Frontend/Dockerfile
則是指定要使用的Dockerfile檔案路徑,而最後面還有一個『 .
』符號,要注意不可省略,那是指定要使用的其他Docker Context相關檔案目錄路徑(也就是目前指令列工作目錄所在的專案根目錄),這樣就可以讓ACR自動執行Dockerfile內的指令,將專案內容打包成容器影像檔。
還有一個 --no-logs
參數,可以不指定,當不指定的時候就會和使用本機端的docker指令一樣,顯示出建置容器影像時docker執行Dockerfile和下載相關依賴影像檔的整個打包過程,那些打包過程實際上是從雲端ACR執行端收集後,再傳送回給地端的azure cli顯示,所以會有一些延遲,而且其實不管有沒有使用該參數來在地端顯示建置記錄,實際上都可以從開始執行azure cli指令之後,畫面上顯示的 Queue a build with ID: ,取得該次建置的ACR task ID,例如下圖的task ID就是 "cr1":
然後再從Azure Portal上ACR服務的Tasks功能頁面查看建置記錄:
假如容器影像檔成功建置的話,在ACR的Webhooks功能頁面上可查看到先前建立有Image Push動作就會自動觸發的webhook發送記錄:
此時ACR的Webhook呼叫會觸發App Service上設定的持續部署機制,自動將 urlshortener/frontend:latest 的容器影像檔版本下載並部署到App Service上,可在App Service的Deployment Center功能頁面的Logs上查看到此流程:
稍等一段時間後,App Service就完成部署,開始能正常提供短網址服務了。
如果要將此版本的容器影像檔增加標籤(image tag),不必用地端的docker指令列下載影像檔、定義標籤後再上傳的方式,可利用Azure Cli的 az acr import
指令的技巧,直接在雲端ACR服務上增加標籤,例如:
az acr import -n <ACR_service_name> --source <ACR_service_name>.azurecr.io/urlshortener/frontend:latest -t urlshortener/frontend:1.0 --force
記得將 <ACR_service_name> 替換成建立起來的Azure Container Registry服務名稱,這就可以將目前在這ACR服務中容器影像檔名稱為 urlshortener/frontend,標籤為 latest 的容器影像版本建立一個『1.0』的標籤,建立之後可用 az acr respository show-tags
指令列出目前 urlshortener/frontend 所有標籤:
az acr repository show-tags -n <ACR_service_name> --repository urlshortener/frontend --output table
執行結果如下:
或使用Azure Portal網頁上ACR服務的 Repositories 功能頁面查看:
使用這個從自己容器影像庫的容器影像檔案匯入自己影像庫的技巧,就能直接在雲端ACR服務上建立容器影像標籤,倘若之後有新版的應用服務要部署時,可依上述流程將當前App Service使用的容器影像建立標籤版本備份保存後,再次發送上述的 az acr build
指令,在雲端ACR服務上建立新版的容器影像檔,並且在App Service上自動部署新版的應用服務了。